package com.lee9213.mybatis.plugin;

import com.lee9213.mybatis.utility.ClassDocUtil;
import com.lee9213.mybatis.utility.DBUtil;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.internal.util.StringUtility;

import java.util.*;

/**
 * mapper生成器
 *
 * @author lee9213@163.com
 * @version 1.0
 * @date 2017/3/29 16:21
 */
public class MapperPlugin extends PluginAdapter {

    private Set<String> mappers = new HashSet<>();
    private String author;
    private String remarks;

    @Override
    public void setProperties(Properties properties) {
        super.setProperties(properties);
        String mappers = this.properties.getProperty("mappers");
        if (StringUtility.stringHasValue(mappers)) {
            String[] caseSensitive = mappers.split(",");
            int beginningDelimiter = caseSensitive.length;
            String schema;
            for (int endingDelimiter = 0; endingDelimiter < beginningDelimiter; ++endingDelimiter) {
                schema = caseSensitive[endingDelimiter];
                this.mappers.add(schema);
            }
        }
        author = this.properties.getProperty("user.name");
        if (author == null || "".equals(author)) {
            author = System.getProperty("user.name");
        }
    }

    @Override
    public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        //添加注释
        addModelClassComment(topLevelClass, introspectedTable);

        //添加时间处理
        List<Field> fields = topLevelClass.getFields();
        boolean flag = false;
        for(int i=0;i<fields.size();i++){
            Field f = fields.get(i);
            if("date".equalsIgnoreCase(f.getType().getShortName())){
                f.addAnnotation("@DateTimeFormat(pattern = \"yyyy-MM-dd HH:mm:ss\")");
                flag = true;
            }
        }
        if(flag){
            topLevelClass.addImportedType(new FullyQualifiedJavaType("org.springframework.format.annotation.DateTimeFormat"));
        }

        return true;
    }
    @Override
    public boolean modelRecordWithBLOBsClassGenerated(TopLevelClass topLevelClass,
                                                      IntrospectedTable introspectedTable) {
        addModelClassComment(topLevelClass, introspectedTable);
        return true;
    }

    /**
     * mapper生成
     *
     * @param interfaze
     * @param topLevelClass
     * @param introspectedTable
     * @return
     */
    @Override
    public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        interfaze.addImportedType(new FullyQualifiedJavaType("org.apache.ibatis.annotations.Mapper"));
        interfaze.addAnnotation("@Mapper");

        FullyQualifiedJavaType entityType = new FullyQualifiedJavaType(introspectedTable.getBaseRecordType());
        interfaze.addImportedType(entityType);

        Iterator<String> iterator = this.mappers.iterator();
        while (iterator.hasNext()) {
            String mapper = iterator.next();
            interfaze.addImportedType(new FullyQualifiedJavaType(mapper));
            interfaze.addSuperInterface(new FullyQualifiedJavaType(mapper + "<" + entityType.getShortName() + ">"));
        }

        //添加注释
        ClassDocUtil.addInterfaceJavaDoc(interfaze,author,remarks);
        List<Method> methods = interfaze.getMethods();
        for(int i=0;i<methods.size();){
            if(methods.size()==0)break;
            methods.remove(i);
        }
        return true;
    }

    /**
     * xml生成
     * @param document
     * @param introspectedTable
     * @return
     */
    @Override
    public boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable) {
        String tableName = introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime();//数据库表名
        XmlElement parentElement = document.getRootElement();
        // 产生分页语句前半部分
        XmlElement element = new XmlElement("select");
        element.addAttribute(new Attribute("id", "query"));
        element.addAttribute(new Attribute("parameterType", "com.i2863.core.page.PageQuery"));
        element.addAttribute(new Attribute("resultMap", "BaseResultMap"));

        element.addElement(new TextElement("select \n" +
                "    <include refid=\"Base_Column_List\" />\n" +
                "    from " + tableName + "\n"));
        parentElement.addElement(element);

        XmlElement element1 = new XmlElement("select");
        element1.addAttribute(new Attribute("id", "count"));
        element1.addAttribute(new Attribute("parameterType", "java.util.Map"));
        element1.addAttribute(new Attribute("resultType", "java.lang.Integer"));
        element1.addElement(new TextElement(
                "                select count(1) from "+tableName+"\n" +
                        "        <where>\n" +
                        "        <foreach collection=\"params\" item=\"item\" index=\"key\" separator=\"and\">\n" +
                        "        <if test=\"item != null\">\n" +
                        "                ${key} = #{item}\n" +
                        "        </if>\n" +
                        "        </foreach>\n" +
                        "        </where>\n"
        ));
        parentElement.addElement(element1);


        /*XmlElement element2 = new XmlElement("select");
        element2.addAttribute(new Attribute("id", "selectPageList"));
        element2.addAttribute(new Attribute("parameterType", "com.sobey.core.ibatis.page.PageQuery"));
        element2.addAttribute(new Attribute("resultType", domainName));

        element2.addElement(new TextElement(
                "        select\n" +
                        "        <include refid=\"Base_Column_List\"/>\n" +
                        "        from "+tableName+"\n" +
                        "        <where>\n" +
                        "            <foreach collection=\"params\" item=\"item\" index=\"key\" separator=\"and\">\n" +
                        "                <if test=\"item != null\">\n" +
                        "                    ${key} = #{item}\n" +
                        "                </if>\n" +
                        "            </foreach>\n" +
                        "        </where>\n" +
                        "        limit #{offset},#{pageSize}\n"
        ));
        parentElement.addElement(element2);*/
        return super.sqlMapDocumentGenerated(document, introspectedTable);
    }
    @Override
    public boolean sqlMapInsertElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        return false;
    }
    @Override
    public boolean sqlMapInsertSelectiveElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        List<Attribute> attrs = element.getAttributes();
        for(int i=0;i<=attrs.size();){
            if(attrs.size() == 0)break;
            attrs.remove(i);
        }
        attrs.add(new Attribute("id", "save"));
        attrs.add(new Attribute("parameterType",introspectedTable.getBaseRecordType()));
        return super.sqlMapInsertSelectiveElementGenerated(element, introspectedTable);
    }

    @Override
    public boolean sqlMapSelectByPrimaryKeyElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        List<Attribute> attrs = element.getAttributes();
        for(int i=0;i<=attrs.size();){
            if(attrs.size() == 0)break;
            attrs.remove(i);
        }
        attrs.add(new Attribute("id", "get"));
        attrs.add(new Attribute("parameterType",introspectedTable.getBaseRecordType()));
        attrs.add(new Attribute("resultMap","BaseResultMap"));

        return super.sqlMapSelectByPrimaryKeyElementGenerated(element, introspectedTable);
    }

    @Override
    public boolean sqlMapDeleteByPrimaryKeyElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        List<Attribute> attrs = element.getAttributes();
        for(int i=0;i<=attrs.size();){
            if(attrs.size() == 0)break;
            attrs.remove(i);
        }
        attrs.add(new Attribute("id", "remove"));
        attrs.add(new Attribute("parameterType",introspectedTable.getBaseRecordType()));
        return super.sqlMapDeleteByPrimaryKeyElementGenerated(element, introspectedTable);
    }
    @Override
    public boolean sqlMapUpdateByPrimaryKeySelectiveElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        List<Attribute> attrs = element.getAttributes();
        for(int i=0;i<=attrs.size();){
            if(attrs.size() == 0)break;
            attrs.remove(i);
        }
        attrs.add(new Attribute("id", "update"));
        attrs.add(new Attribute("parameterType",introspectedTable.getBaseRecordType()));
        return super.sqlMapUpdateByPrimaryKeySelectiveElementGenerated(element, introspectedTable);
    }

    /**
     * 添加model类注释
     *
     * @param topLevelClass
     * @param introspectedTable
     */
    private void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        //获取表描述信息
        remarks = DBUtil.getRemarks(context.getJdbcConnectionConfiguration(),introspectedTable.getFullyQualifiedTable());
        //添加注释
        ClassDocUtil.addClassJavaDoc(topLevelClass,author,remarks);
    }


    @Override
    public boolean validate(List<String> list) {
        return true;
    }

    @Override
    public boolean sqlMapDeleteByExampleElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean sqlMapUpdateByPrimaryKeyWithBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean sqlMapUpdateByExampleSelectiveElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean sqlMapUpdateByPrimaryKeyWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean sqlMapUpdateByExampleWithBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean sqlMapUpdateByExampleWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        return false;
    }
}
